package com.wenqiner.requesttool.util;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.text.CharSequenceUtil;
import com.alibaba.fastjson2.JSON;
import com.wenqiner.requesttool.core.tool.PlaceholderMethod;
import com.wenqiner.requesttool.domain.IntegrityPlaceholder;
import com.wenqiner.requesttool.domain.Placeholder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author rhf
 * @date 2023-02-28
 **/
public class ParsePlaceholderUtil {
    public static final Logger log = LoggerFactory.getLogger(ParsePlaceholderUtil.class);

    /**
     * 方法开始标志的正则
     */
    public static final String METHOD_PREFIX_REGEXP = "\\{\\{";
    /**
     * 方法占位符其实位
     */
    public static final String METHOD_PREFIX = "{{";


    public static final String METHOD_REGEXP = "(\\{\\{|}})";

    /**
     * 方法结束标志的正则
     */
    public static final String METHOD_SUFFIX_REGEXP = "}}";
    /**
     * 方法中参数开始标志的正则
     */
    public static final String PARAM_PREFIX_REGEXP = "\\(";
    /**
     * 方法中参数结束标志的正则
     */
    public static final String PARAM_SUFFIX_REGEXP = "\\)";
    /**
     * 参数分割符号
     */
    public static final String PARAM_DELIMITER = ",";

    /**
     * 解析方法外的数据,如果没有方法的占位符则不处理，例如:
     * awo asx asxasx { quace(#dto.mobile) } xasx {qsax(#dto.mobile)}
     *
     * @param msg 字符串
     * @return java.lang.String
     * @author rhf
     */
    @SuppressWarnings("all")
    public static String parseMethodOuter(String msg) throws Exception {
        if (CharSequenceUtil.isBlank(msg)) {
            return "";
        }
        Pattern pattern = Pattern.compile(METHOD_REGEXP, Pattern.MULTILINE);
        Matcher matcher = pattern.matcher(msg);
        List<Placeholder> placeholders = new ArrayList<>();
        while (matcher.find()) {
            String group = matcher.group();
            Placeholder placeholder = new Placeholder();
            placeholder.setLabel(group);
            if (group.equals(METHOD_PREFIX)) {
                placeholder.setIndex(matcher.start());
            } else {
                placeholder.setIndex(matcher.end());
            }
            placeholders.add(placeholder);
        }
        //没有替换符
        if (CollUtil.isEmpty(placeholders)) {
            return msg;
        }
        Collections.sort(placeholders, Comparator.comparing(Placeholder::getIndex));
        log.debug("获取带有系统函数占位符的参数,符号位[{}]", JSON.toJSONString(placeholders));
        Placeholder[] strings = placeholders.toArray(new Placeholder[placeholders.size()]);
        List<Integer> useIndexList = new ArrayList<>();
        List<IntegrityPlaceholder> integrityPlaceholderList = new ArrayList<>();

        IntegrityPlaceholder integrityPlaceholder = null;
        for (int i = 0; i < strings.length; i++) {
            if (useIndexList.contains(strings[i].getIndex())) {
                continue;
            }
            if (strings[i].getLabel().equals(METHOD_PREFIX)) {
                if (null != integrityPlaceholder && null == integrityPlaceholder.getFinish()) {
                    loopMerge(useIndexList, strings, integrityPlaceholder, 1, i);
                } else {
                    useIndexList.add(strings[i].getIndex());
                    integrityPlaceholder = new IntegrityPlaceholder();
                    integrityPlaceholder.setIndex(strings[i].getIndex());
                    integrityPlaceholderList.add(integrityPlaceholder);
                }
            }
            if (strings[i].getLabel().equals("}}")) {
                useIndexList.add(strings[i].getIndex());
                integrityPlaceholder.setFinish(strings[i].getIndex());
            }
        }

        //处理函数
        return parse(msg, integrityPlaceholderList, 0);
    }

    /**
     * 解析template中方法
     *
     * @param methodTemplate    方法模版
     * @param placeholderMethod 获取方法
     * @return java.lang.String
     * @author rhf
     */
    @SuppressWarnings("all")
    private static String parseMethodInner(String methodTemplate) {
        if (CharSequenceUtil.isBlank(methodTemplate)) {
            return "";
        }
        methodTemplate = methodTemplate.replaceAll(METHOD_PREFIX_REGEXP, "").replaceAll("}", "");
        Pattern parseStart = Pattern.compile(PARAM_PREFIX_REGEXP, Pattern.MULTILINE);
        Matcher matchStart = parseStart.matcher(methodTemplate);
        Pattern parseEnd = Pattern.compile(PARAM_SUFFIX_REGEXP, Pattern.MULTILINE);
        Matcher matchEnd = parseEnd.matcher(methodTemplate);
        boolean startFlag = matchStart.find();
        boolean endFlag = matchEnd.find();
        if (startFlag && endFlag) {
            //方法名
            String methodName = methodTemplate.substring(0, matchStart.start()).trim();
            //参数，多个使用','隔开
            String methodParam = methodTemplate.substring(matchStart.end(), matchEnd.start());
            //后续部分
            String suffix = methodTemplate.substring(matchEnd.end());
            if (CharSequenceUtil.isNotBlank(methodParam)) {
                Object[] parameters = getParameters(methodParam);
                return runMethod(methodName, parameters) + suffix;
            } else {
                return runMethod(methodName) + suffix;
            }

        }
        if (!startFlag && !endFlag) {
            return methodTemplate;
        }
        return methodTemplate;
    }

    /**
     * 获取template中参数的值
     *
     * @param paramStr 方法名称,多个为','隔开
     * @return java.lang.Object[]
     * @author rhf
     */
    private static Object[] getParameters(String paramStr) {
        if (CharSequenceUtil.isBlank(paramStr)) {
            return null;
        }
        return Arrays.stream(paramStr.split(PARAM_DELIMITER))
                .map(String::trim).toArray();

    }

    /**
     * 执行方法
     *
     * @param methodName 方法名称
     * @param obj        参数
     * @return java.lang.String
     * @author rhf
     */
    private static Object runMethod(String methodName, Object... obj) {
        //获取方法,判断是否有参数
        return PlaceholderMethod.getInstance().execute(methodName, obj);
    }


    public static void main(String[] args) {
//        String s = "我吃了{{RANDOMNUMBER(2)}}个苹果,base64转码当前时间戳{{BASE64ENCODER({{TIMESTAMP()}})}}";
//        String s = "我吃了{{RANDOMNUMBER(10)}}个苹果,base64转码当前时间戳{{BASE64ENCODER(xx)}}";
        String s = "{{BASE64ENCODER({{TIMESTAMP()}})}}";

        String parse = null;
        try {
            parse = parseMethodOuter(s);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        System.out.println(parse);
    }

    /**
     * 解析
     *
     * @param originalStr              源字符串
     * @param integrityPlaceholderList 方法占位符
     * @param point                    指针
     * @return java.lang.String
     * @author rhf
     */
    public static String parse(String originalStr, List<IntegrityPlaceholder> integrityPlaceholderList, int point) {
        StringBuilder buffer = new StringBuilder();

        for (IntegrityPlaceholder placeholder : integrityPlaceholderList) {
            buffer.append(originalStr, point, placeholder.getIndex());
            if (null != placeholder.getInners()) {
                String s1 = handlerInnerMethodLoop(originalStr, placeholder.getInners(), placeholder.getIndex());
                buffer.append(s1);
                point = placeholder.getFinish();
            } else {
                String s1 = originalStr.substring(placeholder.getIndex(), placeholder.getFinish());
                buffer.append(parseMethodInner(s1));
                point = placeholder.getFinish();
            }
        }
        buffer.append(originalStr.substring(point));


        return buffer.toString();
    }

    /**
     * 处理方法暂未符调用函数
     *
     * @param s                        原始串
     * @param integrityPlaceholderList 分组
     * @param point                    指针
     * @return java.lang.String
     * @author rhf
     */
    public static synchronized String handlerInnerMethodLoop(String s, List<IntegrityPlaceholder> integrityPlaceholderList, int point) {
        StringBuilder sb = new StringBuilder();
        for (IntegrityPlaceholder placeholder : integrityPlaceholderList) {
            sb.append(s, point, placeholder.getIndex());
            String methodStr = s.substring(placeholder.getIndex(), placeholder.getFinish());
            int i = methodStr.indexOf("(");
            String methodName = methodStr.substring(0, i).replaceAll("\\{", "");
            Object[] params;
            if (null != placeholder.getInners()) {
                String sub = parse(s, placeholder.getInners(), placeholder.getIndex());
                sb.append(parseMethodInner(sub));
                params = getParameters(handlerInnerMethodLoop(s, integrityPlaceholderList, point));
            } else {
                params = getParameters(methodStr.substring(i, methodStr.indexOf(")")).replaceAll(PARAM_PREFIX_REGEXP, ""));
            }
            sb.append(runMethod(methodName, params));
            point = placeholder.getFinish();
        }
        sb.append(s.substring(point));
        return parseMethodInner(sb.toString());
    }


    /**
     * 递归处理函数中嵌套函数的占位符
     *
     * @param useIndexList         已使用占位符
     * @param placeholders         占位符位置
     * @param integrityPlaceholder 完整的占位符信息
     * @param parentStartLevel     上级层数也是开始解决{{x{{}x{{}}}}}情况
     * @param point                指针
     * @author rhf
     */
    public static void loopMerge(List<Integer> useIndexList, Placeholder[] placeholders, IntegrityPlaceholder integrityPlaceholder, int parentStartLevel, int point) {
        IntegrityPlaceholder inner = null;
        for (int j = point; j < placeholders.length; j++) {
            if (useIndexList.contains(placeholders[j].getIndex())) {
                continue;
            }
            if (placeholders[j].getLabel().equals(METHOD_PREFIX)) {
                if (null != inner && null == inner.getFinish()) {
                    loopMerge(useIndexList, placeholders, integrityPlaceholder, 1, j);
                }
                useIndexList.add(placeholders[j].getIndex());
                inner = new IntegrityPlaceholder();
                inner.setIndex(placeholders[j].getIndex());
                List<IntegrityPlaceholder> inners = integrityPlaceholder.getInners();
                if (null == inners) {
                    inners = new ArrayList<>();
                    integrityPlaceholder.setInners(inners);
                }
                inners.add(inner);
            } else {
                assert inner != null;
                if (null != inner.getFinish()) {
                    break;
                }
                useIndexList.add(placeholders[j].getIndex());
                inner.setFinish(placeholders[j].getIndex());

            }
        }
    }

}
